﻿using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml.Linq;
using Microsoft.Practices.Unity;
using XamlaApp.Interfaces;
using XamlaApp.Views;
using XamlaApp.Views.ElementViews;
using XamlaApp.Views.UIViews;

namespace XamlaApp.ViewModels
{
    public class MainUIViewModel : BaseViewModel
    {
        private UserControl _currentPropertyView = Container.AppContainer.Resolve<EmptyPropertiesView>();
        private Stage _stageView;
        private UserControl _currentElement;
        private ControlEditorView _cev;
        private ControlEditorHandle _hTopLeft, _hTop, _hTopRight, _hRight, _hBottomRight, _hBottom, _hBottomLeft, _hLeft;

        #region Properties
        internal UserControl CutCopyBuffer { get; set; }

        internal bool ContainsImages
        {
            get
            {
                return StageView.Children.Any(o => o is ImageView);
            }
        }
        #endregion

        #region Bindable properties
        public SolidColorBrush StageBackgroundColor
        {
            get { return (SolidColorBrush)_stageView.Background; }
            set
            {
                _stageView.Background = value;
                PropertyChanging("StageBackgroundColor");
            }
        }

        private bool _elementSelected;
        public bool ElementSelected
        {
            get { return _elementSelected; }
            set
            {
                _elementSelected = value;
                PropertyChanging("ElementSelected");
            }
        }

        private bool _cutCopyBufferOccupied;
        public bool CutCopyBufferOccupied
        {
            get { return _cutCopyBufferOccupied; }
            set
            {
                _cutCopyBufferOccupied = value;
                UpdateCutCopyBufferPreview();
                PropertyChanging("CutCopyBufferOccupied");
            }
        }

        private WriteableBitmap _bufferedElementPreview;
        public WriteableBitmap BufferedElementPreview
        {
            get { return _bufferedElementPreview; }
            set
            {
                _bufferedElementPreview = value;
                PropertyChanging("BufferedElementPreview");
            }
        }

        private bool _hasElements;
        public bool ProjectHasElements
        {
            get { return _hasElements; }
            set
            {
                _hasElements = value;
                PropertyChanging("ProjectHasElements");
            }
        }

        private bool _imageViewerAvailable;

        public bool ImageViewerAvailable
        {
            get { return _imageViewerAvailable; }
            set
            {
                _imageViewerAvailable = value;
                PropertyChanging("ImageViewerAvailable");
            }
        }

        internal UserControl CurrentElement
        {
            get { return _currentElement; }
            set
            {
                if (_currentElement != null)
                {
                    if (_currentElement.Equals(value)) return;
                    ((IXamlaElement)_currentElement).ViewModel.IsActiveElement = false;

                    //Set the control that is about to be unselected to it's Normal State
                    VisualStateManager.GoToState(_currentElement, "Normal", false);
                }
                _currentElement = value;

                if (_cev != null) RemoveControlEditor();
                if (_currentElement != null)
                {
                    //assign it's property view for binding
                    PropertyView = ((IXamlaElement)_currentElement).Propertyview;

                    //Set the newly selected control to it's Selected state
                    VisualStateManager.GoToState(_currentElement, "Selected", false);

                    //Build up a control editor for it
                    DisplayControlEditor(((IXamlaElement)_currentElement).ViewModel);

                    //set it's isactive property
                    ((IXamlaElement)_currentElement).ViewModel.IsActiveElement = true;

                    //set the bindable boolean
                    ElementSelected = true;
                }
                else
                {
                    ElementSelected = false;
                }

                PropertyChanging("CurrentElement");
            }
        }

        [Dependency]
        public Stage StageView
        {
            get { return _stageView; }
            set
            {
                if (_stageView != null)
                {
                    _stageView.MouseLeftButtonDown -= StageViewMouseLeftButtonDown;
                }
                else
                {
                    _stageView = value;
                    _stageView.Background = new SolidColorBrush(Colors.White);
                    _stageView.ElementsChanged += StageViewElementsChanged;
                }

                _stageView.MouseLeftButtonDown += StageViewMouseLeftButtonDown;
                PropertyChanging("StageView");
            }
        }

        public UserControl PropertyView
        {
            get { return _currentPropertyView; }
            set
            {
                if (value == null)
                {
                    _currentPropertyView = Container.AppContainer.Resolve<EmptyPropertiesView>();
                }
                else
                {
                    _currentPropertyView = value;
                }
                PropertyChanging("PropertyView");
            }
        }

        //TODO: Move this into a dedicated view model for the Element List 
        private ObservableCollection<ElementInfo> _elements = new ObservableCollection<ElementInfo>();
        public ObservableCollection<ElementInfo> ElementInfoList
        {
            get { return _elements; }
            set
            {
                _elements = value;
                PropertyChanging("ElementInfoList");
            }
        }
        #endregion

        #region Event Handlers

        void StageViewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            CurrentElement = null;
            PropertyView = null;
        }

        internal void Element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var c = (UserControl)sender;
            CurrentElement = c;
        }

        internal void StageViewElementsChanged(object sender, EventArgs e)
        {
            //update the element name list collection
            var oc = new ObservableCollection<ElementInfo>();

            foreach (var el in StageView.Children)
            {
                if (el is ControlEditorHandle || el is ControlEditorView) continue;
                oc.Insert(0, new ElementInfo
                {
                    ObjectName = ((IXamlaElement)el).ViewModel.ControlName,
                    ObjectReference = el
                });
            }

            ElementInfoList = oc;

            //update the HasElements flag
            ProjectHasElements = StageView.Children.Any();
        }
        #endregion

        #region Methods

        private void UpdateCutCopyBufferPreview()
        {
            if (CutCopyBuffer == null)
            {
                BufferedElementPreview = null;
                return;
            }

            BufferedElementPreview = new WriteableBitmap(CutCopyBuffer, null);
            BufferedElementPreview.Invalidate();

        }

        public void UpdateControlEditor()
        {
            if (CurrentElement != null)
            {
                var vm = ((IXamlaElement)CurrentElement).ViewModel;
                _cev.Visibility = (vm.EditMode) ? Visibility.Collapsed : Visibility.Visible;
            }
        }

        //remove the control editor components from the stage
        internal void RemoveControlEditor()
        {
            _stageView.UnRegisterDraggableElement(_cev);
            _stageView.Children.Remove(_cev);

            _stageView.UnRegisterDraggableElement(_hTopLeft);
            _stageView.UnRegisterDraggableElement(_hTop);
            _stageView.UnRegisterDraggableElement(_hTopRight);
            _stageView.UnRegisterDraggableElement(_hRight);
            _stageView.UnRegisterDraggableElement(_hBottomRight);
            _stageView.UnRegisterDraggableElement(_hBottom);
            _stageView.UnRegisterDraggableElement(_hBottomLeft);
            _stageView.UnRegisterDraggableElement(_hLeft);

            _stageView.Children.Remove(_hTopLeft);
            _stageView.Children.Remove(_hTop);
            _stageView.Children.Remove(_hTopRight);
            _stageView.Children.Remove(_hRight);
            _stageView.Children.Remove(_hBottomRight);
            _stageView.Children.Remove(_hBottom);
            _stageView.Children.Remove(_hBottomLeft);
            _stageView.Children.Remove(_hLeft);
        }

        internal void DisplayControlEditor(FrameworkElementViewModel vm)
        {
            _cev = new ControlEditorView(vm);
            _stageView.Children.Add(_cev);
            if (!((IXamlaElement)_currentElement).ViewModel.EditMode)
            {
                _stageView.RegisterDraggableElement(_cev, _cev.gridDragSurface);
                _cev.Visibility = Visibility.Visible;
            }
            else
            {
                _cev.Visibility = Visibility.Collapsed;
            }
            _hTopLeft = new ControlEditorHandle(vm, ControlHandleTypes.TopLeft);
            _stageView.Children.Add(_hTopLeft);
            _stageView.RegisterDraggableElement(_hTopLeft);

            _hTop = new ControlEditorHandle(vm, ControlHandleTypes.Top);
            _stageView.Children.Add(_hTop);
            _stageView.RegisterDraggableElement(_hTop);

            _hTopRight = new ControlEditorHandle(vm, ControlHandleTypes.TopRight);
            _stageView.Children.Add(_hTopRight);
            _stageView.RegisterDraggableElement(_hTopRight);

            _hRight = new ControlEditorHandle(vm, ControlHandleTypes.Right);
            _stageView.Children.Add(_hRight);
            _stageView.RegisterDraggableElement(_hRight);

            _hBottomRight = new ControlEditorHandle(vm, ControlHandleTypes.BottomRight);
            _stageView.Children.Add(_hBottomRight);
            _stageView.RegisterDraggableElement(_hBottomRight);

            _hBottom = new ControlEditorHandle(vm, ControlHandleTypes.Bottom);
            _stageView.Children.Add(_hBottom);
            _stageView.RegisterDraggableElement(_hBottom);

            _hBottomLeft = new ControlEditorHandle(vm, ControlHandleTypes.BottomLeft);
            _stageView.Children.Add(_hBottomLeft);
            _stageView.RegisterDraggableElement(_hBottomLeft);

            _hLeft = new ControlEditorHandle(vm, ControlHandleTypes.Left);
            _stageView.Children.Add(_hLeft);
            _stageView.RegisterDraggableElement(_hLeft);


        }

        internal void DeleteCurrentElement()
        {
            StageView.DeleteElement(CurrentElement);
            CurrentElement = null;
            PropertyView = null;
        }

        internal string GenerateXaml()
        {
            //generate the Xaml
            var xamlRoot = XElement.Parse("<Canvas xmlns='http://schemas.microsoft.com/client/2007' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'></Canvas>");

            foreach (var e in StageView.Children.Where(o => !(o is ControlEditorHandle) && !(o is ControlEditorView)))
            {
                ((IXamlaElement)e).ViewModel.GenerateXaml(xamlRoot);
            }

            //NOTE: Not sure why the Xaml generation is leaving empty 'xmlns=""' attributes in each element... just remove them for now
            return xamlRoot.ToString(SaveOptions.None).Replace("xmlns=\"\"", "");
        }
        #endregion
    }
}
